home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 10 code / Is it Art? / ArtMaker / Painterly.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-08  |  23.6 KB  |  863 lines  |  [TEXT/KAHL]

  1. #include    "Painterly.h"
  2.  
  3. /* Painterly Globals */
  4. extern MenuHandle        gPaintMenuHandles[];         /* The menus we add */
  5. extern DocumentRecord    gSrcDoc, gDstDoc;            /* The doc records */
  6. extern CWindowPtr        gSrcWindPtr, gDstWindPtr;    /* the windows */
  7. extern Handle            gCurrentBrushHandle;        /* handle to the current Brush code */
  8. extern short            gCurrentBrushNum;            /* the current Brush menu item */
  9. extern BrushParams        gBrushStuff;                /* the parameter structure for brush calls */
  10. extern Point            gNextPoint;                    /* the next point touched in ordered strokes */
  11. extern short            gOrderedIncrement;
  12. extern Boolean            gPaintingNow, gRandomStrokes;
  13. extern THPrint            gPrintRecHandle;
  14. extern RGBColor            gBGColor;
  15. extern short            gDocTitleHeight;
  16.  
  17. /* These globals are used only by the pict spooling procedures */
  18. OSErr            gPictError;
  19. long            gPictSize;
  20. PicHandle        gPictHandle;
  21. short            gPictFileRef;
  22.  
  23. /* Called when the user selects a filter from the Filter Menu */
  24. void DoFilterMenu(short item)
  25. {    
  26.     short            rslt;
  27.     Str255            filterName;
  28.     Handle            theFilter;
  29.     WindowPtr        wind;
  30.     
  31.     /* Do nothing if the front window isn't ours */
  32.     wind = FrontWindow();
  33.     if(IsAppWindow(wind) == false)
  34.         return;
  35.  
  36.     /* Get the name of the filter */
  37.     GetItem(gPaintMenuHandles[kFilterMenu], item, filterName);
  38.     
  39.     /* Load the filter */
  40.     theFilter = GetNamedResource('FLTR', filterName);
  41.     if(ResError() == noErr && theFilter != nil)
  42.     {
  43.         DocumentPeek    doc;
  44.         
  45.         /* Get the document */
  46.         doc = (DocumentPeek)wind;
  47.         if(doc->world != nil)
  48.         {
  49.             /* Allow an undo */
  50.             SetUpForUndo(wind);
  51.             /* rslt is ignored here: presumably the filter told the user what was wrong */
  52.             rslt = CallFilter(doc->world, theFilter);
  53.             SetPort(wind);
  54.             InvalRect(&wind->portRect);
  55.         }
  56.         ReleaseResource(theFilter);
  57.     }
  58.     else
  59.         DoErrorAlert(kNoFilterStr, 0);
  60. }
  61.  
  62. void DoBrushMenu(short item)
  63. {
  64.     switch(item)
  65.     {
  66.         case iPenSize:
  67.             PenDlog();
  68.             break;
  69.         
  70.         case iConfigureBrush:
  71.             CallBrush(kConfigure, &gBrushStuff, gCurrentBrushHandle);
  72.             break;
  73.         
  74.         default:    /* A brush selected */
  75.         {
  76.             short        rslt;
  77.     
  78.             /* if the selected brush is the same as the current one, do nothing */
  79.             if(item == gCurrentBrushNum)
  80.                 break;
  81.             
  82.             /* Set up the new brush */
  83.             rslt = SetCurrentBrush(item);
  84.             if(rslt == noErr)
  85.             {
  86.                 long    flags;
  87.                 
  88.                 /* We switched successfully. If the Configure item is enabled, 
  89.                 configure the brush. */
  90.                 flags = (**gPaintMenuHandles[kBrushMenu]).enableFlags;
  91.                 if( flags & (1L << iConfigureBrush) )
  92.                 {
  93.                     /* The item is enabled, so go ahead and configure */
  94.                     CallBrush(kConfigure, &gBrushStuff, gCurrentBrushHandle);
  95.                 }
  96.             }
  97.             break;
  98.         }
  99.     }
  100. }
  101.  
  102. void DoPaintMenu(short item)
  103. {
  104.     CGrafPtr    oldport;
  105.     GDHandle    olddev;
  106.     Str255        itemText;
  107.     
  108.     switch(item)
  109.     {
  110.         case iSetup:
  111.             AutoPaintSetupDlog();
  112.             break;
  113.  
  114.         case iStartPainting:  /* Go/Stop */
  115.             if(gPaintingNow == true)
  116.             {
  117.                 /* Stopping painting... */
  118.                 SetItem(gPaintMenuHandles[kAutoPaintMenu], iStartPainting, 
  119.                             TheStr(itemText, kStartPainting));
  120.                 gPaintingNow = false;
  121.                 
  122.                 /* Reset the point for ordered strokes */
  123.                 gNextPoint.h = 0;
  124.                 gNextPoint.v = 0;
  125.             }
  126.             else
  127.             {
  128.                 /* Starting painting, allow undo */
  129.                 SetUpForUndo(gDstWindPtr);
  130.                 SetItem(gPaintMenuHandles[kAutoPaintMenu], iStartPainting,
  131.                             TheStr(itemText, kStopPainting));
  132.                 gPaintingNow = true;
  133.             }
  134.             break;
  135.     }
  136. }
  137.  
  138. /*     This routine runs the "Save Changes" dialogs, if needed, and responds appropriately.
  139.     It returns true if the caller should proceed, or false if the user cancels the save. */
  140. Boolean SaveCurrentDocs(void)
  141. {
  142.     short        rslt;
  143.     Boolean        quit = true;
  144.     
  145.     /* First make sure there is a document open. If not, just return true */
  146.     if(((WindowPeek)&gSrcDoc)->visible != true)
  147.         return quit;
  148.         
  149.     /* If the Src window needs saving, do the dialog */
  150.     if(gSrcDoc.dirty)
  151.     {
  152.         /* Bring the window to the front, and process activate and update events */
  153.         SelectWindow(gSrcWindPtr);
  154.         DoActivateUpdate();
  155.         rslt = SaveChangesDlog();
  156.         switch(rslt)
  157.         {
  158.             case 1:    /* Save */
  159.                 quit = !AppSave(); /*    AppSave() returns true only if the user 
  160.                                         canceled the StandardFile dialog, or if
  161.                                         there was an error, in which case we should 
  162.                                         cancel */
  163.                 break;
  164.             
  165.             case 4:    /* No save */    
  166.                 quit = true;
  167.                 break;
  168.             
  169.             case 2:    /* Cancel */
  170.                 quit = false;
  171.                 break;
  172.         }
  173.     }
  174.     
  175.     /* Keep going? */
  176.     if(quit)
  177.     {
  178.         /* If the Dst window needs saving, do the dialog */
  179.         if(gDstDoc.dirty)
  180.         {
  181.             /* Bring the window to the front, and process activate and update events */
  182.             SelectWindow(gDstWindPtr);
  183.             DoActivateUpdate();
  184.             rslt = SaveChangesDlog();
  185.             switch(rslt)
  186.             {
  187.                 case 1:    /* Save */
  188.                     quit = !AppSave(); /*    AppSave() returns true only if the user 
  189.                                             canceled the StandardFile dialog, or if
  190.                                             there was an error, in which case we should 
  191.                                             cancel */
  192.                     break;
  193.                 
  194.                 case 4:    /* No save */    
  195.                     quit = true;
  196.                     break;
  197.                 
  198.                 case 2:    /* Cancel */
  199.                     quit = false;
  200.                     break;
  201.             }
  202.         }
  203.     }
  204.     return quit;    
  205. }
  206.  
  207. /* This routine positions and sizes the windows (assumed hidden) appropriately 
  208. for a "new" document and then shows them. The GWorlds are assumed to be already
  209. set up. */
  210. void SetUpAndShowWindows(void)
  211. {
  212.     Rect        deviceRect, docRect;
  213.     GDHandle    theDevice;
  214.     short         stagger = 32, horSize, verSize, wTop, wLeft;
  215.     
  216.     /* Set up a rect on the deepest device that is inset 4 pixels from the edges.
  217.         Note that if it is the Main device we have to take into account the menu bar. */
  218.     deviceRect = (**GetGrayRgn()).rgnBBox;     /* Get rect of entire desktop */
  219.     theDevice = GetMaxDevice(&deviceRect);    /* Get the deepest device */
  220.     deviceRect = (*theDevice)->gdRect;        /* Get its rect */
  221.     InsetRect(&deviceRect, 4, 4);            /* Leave a 4 pixel border on the edges */
  222.     if(theDevice == GetMainDevice())        /* Add the menu bar height if the main device */
  223.         deviceRect.top += GetMBarHeight();
  224.     
  225.     docRect = gSrcDoc.world->portRect;    /* top left is always 0, 0 */
  226.     
  227.     /* OK, first the source window. Need to add the height of the title bar 
  228.         to the vertical coordinate */
  229.     wLeft = deviceRect.left;
  230.     wTop = deviceRect.top + gDocTitleHeight;
  231.     MoveWindow(gSrcWindPtr, wLeft, wTop, false);
  232.     
  233.     /* Now calculate a good size for the window. We'd like to make it the full size of the 
  234.     GWorld (plus scroll bars), but if it would then hang over the edges of the screen,
  235.     we make it smaller. */
  236.     horSize = docRect.right + kScrollAdjust;
  237.     if(wLeft + horSize > deviceRect.right) /* hangs off the right */
  238.         horSize = deviceRect.right - wLeft;
  239.     verSize = docRect.bottom + kScrollAdjust;
  240.     if(wTop + verSize > deviceRect.bottom) /* hangs off the bottom */
  241.         verSize = deviceRect.bottom - wTop;
  242.     
  243.     /* Size it, and reset the clip */
  244.     SizeWindow(gSrcWindPtr, horSize, verSize, false);
  245.     SetPort(gSrcWindPtr);
  246.     ClipRect(&gSrcWindPtr->portRect);
  247.     
  248.     /* Now the destination window */
  249.     wTop += stagger;
  250.     wLeft += stagger;
  251.     MoveWindow(gDstWindPtr, wLeft, wTop, false);
  252.     
  253.     /* Use the same sizes as for the source, unless it hangs off the edge */
  254.     if(wLeft + horSize > deviceRect.right) /* hangs off the right */
  255.         horSize = deviceRect.right - wLeft;
  256.     if(wTop + verSize > deviceRect.bottom) /* hangs off the bottom */
  257.         verSize = deviceRect.bottom - wTop;
  258.     
  259.     /* Size it, and reset the clip */
  260.     SizeWindow(gDstWindPtr, horSize, verSize, false);
  261.     SetPort(gDstWindPtr);
  262.     ClipRect(&gDstWindPtr->portRect);
  263.     
  264.     /* Make sure the scrollbars are presentable */
  265.     AdjustScrollbars(gSrcWindPtr, true);
  266.     AdjustScrollbars(gDstWindPtr, true);
  267.     
  268.     /* OK, we're ready. Show the windows, putting the source in front */
  269.     ShowWindow(gSrcWindPtr);
  270.     ShowWindow(gDstWindPtr);
  271.  
  272.     /* Enable the appropriate menus */
  273.     EnableItem(gPaintMenuHandles[kFilterMenu], 0);
  274.     EnableItem(gPaintMenuHandles[kBrushMenu], 0);
  275.     EnableItem(gPaintMenuHandles[kAutoPaintMenu], 0);
  276.     DrawMenuBar();
  277. }    
  278.     
  279.     
  280. /* Opens the file indicated by fileSpec, reads the pict into the GWorlds, 
  281. and creates a new document, showing the windows. This routine is ugly as
  282. hell and WAY too big. Sorry about that. Would you believe an exercise for the
  283. reader? Didn't think so. I do think it's a pretty safe rouine, just real ugly...*/
  284. OSErr ReadPICTFileToNewWorlds(FSSpec *fileSpec)
  285. {
  286.     OSErr            err;
  287.     long            readSize, pictSize;
  288.     short            refNum;
  289.     CQDProcs        *oldProcs, newProcs;
  290.     Picture            thePict;
  291.     CursHandle        Curs;
  292.     
  293.     /* Open the file, get the size of the pict, and read in just the Picture
  294.     structure (picSize and picFrame) so we can get the size of the GWorlds
  295.     we need, */
  296.     err = FSpOpenDF(fileSpec, fsWrPerm, &refNum);
  297.     if(err == noErr)
  298.     {
  299.         /* Get the size of the pict in the file */
  300.         err = GetEOF(refNum, &pictSize);
  301.         if(err == noErr)
  302.         {
  303.             /* subtract standard PICT header length */
  304.             pictSize -= kPICTHeaderSize;
  305.             /* Set the file marker to the start of the PICT data */
  306.             err = SetFPos(refNum, fsFromStart, (long)kPICTHeaderSize);
  307.             if(err == noErr)
  308.             {
  309.                 readSize = sizeof(Picture);
  310.                 err = FSRead(refNum, &readSize, &thePict);
  311.             }
  312.         }
  313.     
  314.         /*  Now build the GWorlds */
  315.         if(err == noErr)
  316.         {
  317.             /* Try to Build the new GWorlds */
  318.             if(InitGlobalGWorlds(&thePict.picFrame) == true)
  319.             {
  320.                 /* Set the cursor to a watch, this may take a while */
  321.                 Curs = GetCursor(watchCursor);
  322.                 if(Curs != nil)
  323.                     SetCursor(*Curs);
  324.                 
  325.                 /* Allocate the pict handle, installing spooling if we're low on memory.
  326.                 then call DrawPictOff to draw the picture offscreen.  */
  327.                 
  328.                 /* Try the quick and dirty method, allocating the pict in Temp Mem
  329.                 or app mem */
  330.                 gPictHandle = (PicHandle)TempNewHandle(pictSize, &err);
  331.                 if(gPictHandle == nil) /* Try for app mem, and reset error */
  332.                 {
  333.                     err = noErr;
  334.                     gPictHandle = (PicHandle)NewHandle(pictSize);
  335.                 }
  336.                 
  337.                 /* If it worked, we got off easy. Read the pict in and draw it. */    
  338.                 if(gPictHandle != nil)
  339.                 {
  340.                     /* Set position back to just after the file header */
  341.                     err = SetFPos(refNum, fsFromStart, (long)kPICTHeaderSize);
  342.                     if(err == noErr)
  343.                     {
  344.                         err = FSRead(refNum, &pictSize, *gPictHandle);
  345.                         if(err == noErr)
  346.                         {
  347.                             DrawPictOff(gSrcDoc.world, gPictHandle);
  348.                         }
  349.                     }
  350.                     DisposHandle(gPictHandle);
  351.                     gPictHandle = nil;
  352.                 }
  353.                 else
  354.                 {
  355.                     /* No such luck, need to spool in the pict. First allocate a little
  356.                         handle to get it started */
  357.                     gPictHandle = (PicHandle)(NewHandleClear(sizeof(Picture)));
  358.                     if(gPictHandle != nil)
  359.                     {
  360.                         /* Copy the Picture data we read in earlier. the file position is
  361.                         still at the start of the pict data */
  362.                         **gPictHandle = thePict;
  363.                         
  364.                         /* save old grafProcs */
  365.                         oldProcs = gSrcDoc.world->grafProcs;
  366.                         
  367.                         /* Initialize the new procs with default values, then insert our 
  368.                         custom    getPic Proc and install in the world */
  369.                         SetStdCProcs(&newProcs);
  370.                         newProcs.getPicProc = PictReader;
  371.                         gSrcDoc.world->grafProcs = &newProcs;
  372.                         
  373.                         /* Now set up the globals that PictReader needs */
  374.                         gPictError = noErr;
  375.                         gPictFileRef = refNum;
  376.                         
  377.                         /* Finally, draw the Picture in the world and throw it away */
  378.                         DrawPictOff(gSrcDoc.world, gPictHandle);
  379.                         DisposHandle(gPictHandle);
  380.                         gPictHandle = nil;
  381.                         
  382.                         /* Restore old grafProcs */
  383.                         gSrcDoc.world->grafProcs = oldProcs;
  384.                         
  385.                         /* if there was a read error, post it */
  386.                         err = gPictError;
  387.                     }
  388.                     else
  389.                         err = memFullErr;
  390.                 }
  391.             }
  392.             else
  393.             {
  394.                 /* Couldn't make the new GWorlds */
  395.                 err = memFullErr;
  396.             }
  397.         }
  398.  
  399.         if(err == noErr)
  400.         {
  401.             Str255    newTitle, fileName;
  402.     
  403.             /* The picture is drawn in the world and order is restored. Now we need to
  404.              do the bookkeeping    and make a real document to show the user */
  405.             
  406.             /* First reset the BrushParams, so brushes don't get confused. */
  407.             gBrushStuff.pt.h = 0;
  408.             gBrushStuff.pt.v = 0;
  409.             gBrushStuff.rect = thePict.picFrame;
  410.             gBrushStuff.theSource = gSrcDoc.world;
  411.             gBrushStuff.theDestination = gDstDoc.world;
  412.                 
  413.             /* Reset Src and Dst file names to empty, so Save does a SaveAs */
  414.             *gSrcDoc.fileSpec.name = 0;
  415.             *gDstDoc.fileSpec.name = 0;
  416.     
  417.             /* Rename the window to match the file name */
  418.             SetWTitle(gSrcWindPtr, fileSpec->name);
  419.             
  420.             /* Cheater conversion from Str63 to Str255 */
  421.             GetWTitle(gSrcWindPtr, fileName);
  422.             /*     If the strings aren't too long, rename the dst to
  423.                 "<filename>Art?", otherwise just "Art?" */
  424.             if(PStrCat(fileName, TheStr(newTitle, kArtStr), true) != nil)
  425.                 SetWTitle(gDstWindPtr, fileName);
  426.             else
  427.                 SetWTitle(gDstWindPtr, TheStr(newTitle, kArtStr));
  428.             
  429.             /* Set the dirty flags */
  430.             gSrcDoc.dirty = false; /* no need to save unless it changes */
  431.             gDstDoc.dirty = false; /* assume no one wants to save an empty picture */
  432.             
  433.             /* Finally, reset and show the windows */
  434.             SetUpAndShowWindows();
  435.         }
  436.         
  437.         /* Close the file and restore the cursor */
  438.         FSClose(refNum);
  439.         InitCursor();
  440.     }
  441.     return err;
  442. }
  443.         
  444.         
  445.         
  446.         
  447.  
  448.  
  449. /* Man, it's a pain when people want to replace an existing file. We go through this 
  450. every time someone saves a document. Sheesh! */
  451. OSErr WorldToExistingFile(FSSpec *fileSpec, GWorldPtr world)
  452. {
  453.     OSErr    err;
  454.     long    tempLong;
  455.     short    tempRefNum;
  456.     Str255    tempName;
  457.     FSSpec    tempSpec;
  458.     FInfo    finderStuff;
  459.  
  460.     /* Make a unique file name */
  461.     GetDateTime(&tempLong);
  462.     NumToString(tempLong, tempName);
  463.     
  464.     /* locate the temporary items folder */
  465.     err = FindFolder(fileSpec->vRefNum, kTemporaryFolderType, kCreateFolder,
  466.                         &tempRefNum, &tempLong);
  467.     if(err == noErr)
  468.     {
  469.         /* Make a new FSSpec */
  470.         err = FSMakeFSSpec(tempRefNum, tempLong, tempName, &tempSpec);
  471.         if(err == noErr || err == fnfErr)
  472.         {
  473.             /* Create the temp file */
  474.             err = FSpCreate(&tempSpec, 'trsh', 'trsh', smSystemScript);
  475.             if(err == noErr)
  476.             {
  477.                 /* OK, we have a new temp file, let's write to it */
  478.                 err = WriteWorldToPICTFile(&tempSpec, world);
  479.                 if(err == noErr)
  480.                 {
  481.                     /* Lookin' good. Now, we need to exchange the data, set the Finder
  482.                         Info of the old (now new) file, and delete the temp file */
  483.                     err = FSpExchangeFiles(&tempSpec, fileSpec);
  484.                     if(err == noErr)
  485.                     {
  486.                         /* First get the existing finder Info */
  487.                         err = FSpGetFInfo(fileSpec, &finderStuff);
  488.                         if(err == noErr)
  489.                         {
  490.                             /* then set it to our type and creator */
  491.                             finderStuff.fdType = 'PICT';
  492.                             finderStuff.fdCreator = 'ART?';
  493.                             /* Don't care about this error: we did our best, by golly */
  494.                             FSpSetFInfo(fileSpec, &finderStuff);
  495.                         }
  496.                     }
  497.                 }
  498.                 /*     We successfully created the temp file, so now delete it,
  499.                     whatever else may have happened. If we can't, there's 
  500.                     nothing we can do about it, so this error is ignored */
  501.                 FSpDelete(&tempSpec);
  502.             }
  503.         }
  504.     }
  505.     return err;
  506. }
  507.  
  508. /* It's much easier just to creat a new file */
  509. OSErr WorldToNewFile(FSSpec *fileSpec, GWorldPtr world)
  510. {
  511.     OSErr    err;
  512.  
  513.     err = FSpCreate(fileSpec, 'ART?', 'PICT', smSystemScript);
  514.     if(err == noErr)
  515.     {
  516.         err = WriteWorldToPICTFile(fileSpec, world);
  517.         /* If there were errors, delete the file */
  518.         if(err != noErr)
  519.             FSpDelete(fileSpec);
  520.     }
  521.     return err;
  522. }
  523.  
  524. /* Opens the file indicated by fileSpec, spools out the GWorld as a pict, and closes the 
  525. file.  
  526. This routine is ugly as
  527. hell and WAY too big. Sorry about that. Would you believe an exercise for the
  528. reader? Didn't think so. I do think it's a pretty safe rouine, just real ugly...*/
  529. OSErr WriteWorldToPICTFile(FSSpec *fileSpec, GWorldPtr world)
  530. {
  531.     CGrafPtr        oldport;
  532.     GDHandle        olddev;
  533.     OSErr            err;
  534.     long            writeSize;
  535.     short            refNum;
  536.     Ptr                zeros;
  537.     CQDProcs        *oldProcs, newProcs;
  538.     
  539.     GetGWorld(&oldport, &olddev);
  540.  
  541.     /* First open the file */
  542.     err = FSpOpenDF(fileSpec, fsWrPerm, &refNum);
  543.     if(err == noErr)
  544.     {
  545.         /* Write out zeros for header bytes */
  546.         writeSize = kPICTHeaderSize;
  547.         zeros = NewPtrClear(writeSize);
  548.         if(zeros != nil)
  549.         {
  550.             err = FSWrite(refNum, &writeSize, zeros);
  551.         }
  552.         else
  553.         {
  554.             /* Bummer, memory's really tight, do it the long way, 128 longs */
  555.             long    cnt, zero = 0;
  556.             
  557.             writeSize = 4;
  558.             for(cnt = 0; cnt < 128; cnt++)
  559.             {
  560.                 err = FSWrite(refNum, &writeSize, &zero);
  561.                 if(err != noErr)
  562.                     break;
  563.             }
  564.         }
  565.         
  566.         /* Try the quick and dirty method, allocating the pict in app RAM (doesn't
  567.         work unless there's a large, contiguous pile of spare memory */
  568.         gPictHandle = WorldToPict(world);
  569.         if(gPictHandle != nil)
  570.         {
  571.             /* How about that, it worked */
  572.             writeSize = GetHandleSize(gPictHandle);
  573.             err = FSWrite(refNum, &writeSize, *gPictHandle);
  574.             KillPicture(gPictHandle);
  575.             gPictHandle = nil;
  576.         }
  577.         else
  578.         {
  579.             /* Do it the slower, safer way */
  580.             
  581.             /* Set the marker to the beginning of the pict data, skipping over the 
  582.             picSize and picFrame fields (those'll be updated when we're done. Be sure the
  583.             file is big enough before doing so. */
  584.             if(err == noErr)
  585.             {
  586.                 err = SetEOF(refNum, kPICTHeaderSize + sizeof(Picture));
  587.                 if(err == noErr)
  588.                     err = SetFPos(refNum, fsFromStart, kPICTHeaderSize + sizeof(Picture));
  589.             }
  590.             
  591.             /* OK, the file is ready to accept the PICT data. Now we need to
  592.             set up the QDProcs in our GWorld so that it will get written. */
  593.             if(err == noErr)
  594.             {
  595.                 /* Move to the GWorld, save the old procs */
  596.                 SetGWorld(world, nil);
  597.                 oldProcs = world->grafProcs;
  598.                 
  599.                 /* Initialize the new procs with default values, then insert our custom
  600.                 putPic Proc and install in the world */
  601.                 SetStdCProcs(&newProcs);
  602.                 newProcs.putPicProc = PictWriter;
  603.                 world->grafProcs = &newProcs;
  604.                 
  605.                 /* Now set up the globals that PictWriter needs */
  606.                 gPictError = noErr;
  607.                 gPictSize = sizeof(Picture); /* Starting size of the pict is just the 
  608.                                                 size of the picSize and picFrame fields */
  609.                 gPictFileRef = refNum;
  610.                 gPictHandle = nil; /* This is important! OpenPicture calls PictWriter
  611.                                         BEFORE the handle is allocated, so it needs to 
  612.                                         be nil going in. */
  613.                 
  614.                 /* OK, finally we get to do the dirty. Open a picture, copybits the world
  615.                 to itself, and close the picture */
  616.                 if(LockWorld(world))
  617.                 {
  618.                     ForeColor(blackColor);
  619.                     gPictHandle = OpenPicture(&world->portRect);
  620.                     CopyBits(*GetGWorldPixMap(world), *GetGWorldPixMap(world), 
  621.                             &world->portRect, &world->portRect, srcCopy, nil);
  622.                     ClosePicture();
  623.                     UnlockWorld(world);
  624.                     err = noErr;
  625.                 }
  626.                 else
  627.                     /* Couldn't lock the world's pixels, so post a generic error */
  628.                     err = -1;
  629.                 
  630.                 /* Check both possible errors */
  631.                 if(gPictError == noErr && err == noErr)
  632.                 {
  633.                     /* Hot Dawg! Got our pict data out. But we're not done yet. Now we need to
  634.                     write the (now correct) header info (not the FILE header, but the picSize
  635.                     and picFrame fields of the pict data). */
  636.                     err = SetFPos(refNum, fsFromStart, kPICTHeaderSize);
  637.                     if(err == noErr)
  638.                     {
  639.                         writeSize = sizeof(Picture);
  640.                         FSWrite(refNum, &writeSize, *gPictHandle);
  641.                     }
  642.                 }
  643.                 
  644.                 /* Restore the GrafProcs and kill the picture */
  645.                 world->grafProcs = oldProcs;
  646.                 KillPicture(gPictHandle);
  647.                 gPictHandle = nil;
  648.                 SetGWorld(oldport, olddev);
  649.             }
  650.         }
  651.         
  652.         /* Close the file. If there were errors, the file is deleted by the caller, who
  653.         created it in the first place */
  654.         FSClose(refNum);
  655.     }
  656.     return err;
  657. }
  658.     
  659. /* Prints the specified world. This is a plain vanilla print loop. */            
  660. void Print(GWorldPtr world)
  661. {
  662.     short            err;
  663.     CGrafPtr        oldport;
  664.     GDHandle        olddev;
  665.     
  666.     GetGWorld(&oldport, &olddev);
  667.     MoveHHi((Handle)gPrintRecHandle);
  668.     HLock((Handle)gPrintRecHandle);
  669.     PrOpen();                                /*  Open Print Mgr  */
  670.     err = PrError();                        /*  Check for errors  */
  671.     if(err == noErr)
  672.     {
  673.         Boolean        OKclicked;
  674.         
  675.         OKclicked = PrJobDialog(gPrintRecHandle);    /*  Run print dialog */
  676.         err = PrError();                    /*  Check for errors  */
  677.         if(err == noErr && OKclicked)
  678.         {
  679.             short        numCopies, copy;
  680.             DialogPtr    dptr;
  681.             
  682.             /* Put up the "To cancel printing..." dialog */    
  683.             dptr = GetNewDialog(kPrintingNowDlogID, nil, (Ptr)(-1));
  684.             if(dptr != nil)
  685.                 DrawDialog(dptr);
  686.             
  687.             /* Only print one page, but possibly lots 'o copies */
  688.             (*gPrintRecHandle)->prJob.iFstPage = 1;
  689.             (*gPrintRecHandle)->prJob.iLstPage = 1;
  690.             numCopies = (*gPrintRecHandle)->prJob.iCopies;
  691.             for(copy = 1; copy <= numCopies; copy++)
  692.             {
  693.                 TPPrPort        printPort;
  694.                 
  695.                 printPort = PrOpenDoc(gPrintRecHandle, nil, nil);
  696.                 err = PrError();
  697.                 if(err == noErr)
  698.                 {
  699.                     PrOpenPage(printPort, nil);
  700.                     err = PrError();
  701.                     if(err == noErr)
  702.                     {
  703.                         Rect    pageRect, dstRect;
  704.                         Point    ctr;
  705.                         
  706.                         dstRect = world->portRect;
  707.                         pageRect = (**gPrintRecHandle).prInfo.rPage;
  708.                         ctr = Center(&pageRect);
  709.                         CenterRect(&dstRect, &ctr);
  710.                         if(LockWorld(world))
  711.                         {
  712.                             CopyBits(*GetGWorldPixMap(world), &printPort->gPort.portBits,
  713.                                     &world->portRect, &dstRect, srcCopy, nil);
  714.                             UnlockWorld(world);
  715.                         }
  716.                     }
  717.                     PrClosePage(printPort);
  718.     
  719.                 }
  720.                 PrCloseDoc(printPort);
  721.             } /* copies loop */
  722.             if(dptr != nil)
  723.                 DisposDialog(dptr);
  724.  
  725.             if((**gPrintRecHandle).prJob.bJDocLoop == bSpoolLoop && PrError() == noErr)
  726.             {
  727.                 TPrStatus    dummy;
  728.  
  729.                 PrPicFile(gPrintRecHandle, nil, nil, nil, &dummy);
  730.             }
  731.         }
  732.     }
  733.     else
  734.         DoErrorAlert(kNoPrinterStr, 0);
  735.         
  736.     PrClose();
  737.     SetGWorld(oldport, olddev);
  738.     HUnlock((Handle)gPrintRecHandle);
  739. }
  740.  
  741.  
  742. /******************************************************************
  743.  
  744. Filter routines
  745.  
  746. *******************************************************************/
  747.  
  748. void BuildFilterMenu(MenuHandle menu)
  749. {
  750.     /* Piece 'o cake, this */
  751.     AddResMenu(menu, 'FLTR');
  752. }
  753.  
  754. short CallFilter(GWorldPtr world, Handle theFilter)
  755. {
  756.     short        result;
  757.     FilterFunc    filter;
  758.     
  759.     if(theFilter == nil)
  760.         return noErr;        /* Don't do anything */
  761.         
  762.     MoveHHi(theFilter);
  763.     HLock(theFilter);
  764.     filter = (FilterFunc)(*theFilter);
  765.     filter = StripAddress(filter); /* Just in case the filter swaps modes */
  766.     result = filter(world);
  767.     HUnlock(theFilter);
  768.     return result;
  769. }
  770.  
  771. /******************************************************************
  772.  
  773. Brush routines
  774.  
  775. *******************************************************************/
  776.  
  777. void BuildBrushMenu(MenuHandle menu)
  778. {
  779.     /* Piece 'o cake, this */
  780.     AddResMenu(menu, 'BRSH');
  781. }
  782.  
  783.  
  784. short CallBrush(short msg, BrushParams *params, Handle theBrush)
  785. {
  786.     short        result;
  787.     BrushFunc    brush;
  788.     
  789.     if(theBrush == nil)
  790.         return noErr;        /* Don't do anything */
  791.         
  792.     MoveHHi(theBrush);
  793.     HLock(theBrush);
  794.     brush = (BrushFunc)(*theBrush);
  795.     brush = StripAddress(brush); /* Just in case the brush swaps modes */
  796.     result = brush(msg, params);
  797.     HUnlock(theBrush);
  798.     return result;
  799. }
  800.  
  801.  
  802. /* This routine gets the new brush, kills the old one, and adjusts the menus */
  803. OSErr SetCurrentBrush(short brushNum)
  804. {
  805.     Str255            brushName;
  806.     Handle            newBrush;
  807.     BrushParams        tempStuff;
  808.     OSErr             rslt = -1; /* generic error */
  809.     
  810.     /* If the brushNum is the same as the current brush, just restart the brush. */
  811.     if(brushNum == gCurrentBrushNum)
  812.     {
  813.         CallBrush(kStopBrush, &gBrushStuff, gCurrentBrushHandle);
  814.         CallBrush(kStartBrush, &gBrushStuff, gCurrentBrushHandle);
  815.         rslt = noErr;
  816.     }
  817.     else /* really a new brush */
  818.     {
  819.         /* Get the name of the brush */
  820.         GetItem(gPaintMenuHandles[kBrushMenu], brushNum, brushName);
  821.         
  822.         /* Load the brush */
  823.         newBrush = GetNamedResource('BRSH', brushName);
  824.         if(ResError() == noErr && newBrush != nil)
  825.         {
  826.             /* Start it up */
  827.             tempStuff = gBrushStuff; /* copy the BrushParams */
  828.             rslt = CallBrush(kStartBrush, &tempStuff, newBrush);
  829.             if(rslt >= 0)
  830.             {
  831.                 /* Looks good, Kill old brush */
  832.                 if(gCurrentBrushHandle != nil)
  833.                 {
  834.                     CallBrush(kStopBrush, &gBrushStuff, gCurrentBrushHandle);
  835.                     ReleaseResource(gCurrentBrushHandle);
  836.                     gBrushStuff.storage = (long)nil;
  837.                 }
  838.                 
  839.                 /* make tempStuff the real thing */
  840.                 gBrushStuff = tempStuff;
  841.                 
  842.                 /* Adjust Menus */
  843.                 CheckItem(gPaintMenuHandles[kBrushMenu], gCurrentBrushNum, false);
  844.                 CheckItem(gPaintMenuHandles[kBrushMenu], brushNum, true);
  845.     
  846.                 if(rslt & kConfigMask) /* A configurable brush, Enable the menu item */
  847.                     EnableItem(gPaintMenuHandles[kBrushMenu], iConfigureBrush);
  848.                 else
  849.                     DisableItem(gPaintMenuHandles[kBrushMenu], iConfigureBrush);
  850.     
  851.                 /* Set the globals and rslt */
  852.                 gCurrentBrushHandle = newBrush;
  853.                 gCurrentBrushNum = brushNum;
  854.                 rslt = noErr;
  855.             }
  856.         }
  857.         else
  858.             DoErrorAlert(kNoBrushStr, 0);
  859.     }
  860.     return rslt;
  861. }
  862.  
  863.